package com.example.springsecurity05.config;

import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.util.Map;

/**
 * 自定义前后端按分离认证的filter
 */
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
//        1、如果请求方式不是post，则抛出异常
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("认证请求方式不支持" + request.getMethod());
        }
//        2、判断请求内容是否是json格式的数据请求，将其转为java格式，并获得对应的uname和passwd
        if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)){
            try {
//                从请求中获得用户信息
                Map<String, String> userInfo = new ObjectMapper().readValue(request.getInputStream(), Map.class);
                String username = userInfo.get(getUsernameParameter());
                String password = userInfo.get(getPasswordParameter());
//                request.getInputStream()流只能获得一次，用户登录认证成功时，把前端传递的参数remember-me写入到request中，便于在自定义的rememberMeServices中获得该参数
                String rememberMe = userInfo.get(AbstractRememberMeServices.DEFAULT_PARAMETER);
                if (!ObjectUtils.isEmpty(rememberMe)) {
                    request.setAttribute(AbstractRememberMeServices.DEFAULT_PARAMETER, rememberMe);
                }
//                以下代码抄袭UsernamePasswordAuthenticationFilter类中，attemptAuthentication的代码实现
                UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username, password);
                this.setDetails(request, authRequest);
                return this.getAuthenticationManager().authenticate(authRequest);
            } catch (StreamReadException e) {
                throw new RuntimeException(e);
            } catch (DatabindException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return super.attemptAuthentication(request, response);
    }
}
